package com.maozzi.api.auth;

import com.google.gson.Gson;
import com.maozzi.api.auth.annotation.RequirePermissions;
import com.maozzi.api.auth.constant.AuthConstant;
import com.maozzi.api.auth.enums.UserTypeEnum;
import com.maozzi.api.auth.model.UserInfo;
import com.maozzi.api.auth.properties.AuthProperties;
import com.maozzi.common.enums.BizCodeEnum;
import com.maozzi.common.exception.BizException;
import com.maozzi.common.model.ResultVO;
import com.maozzi.common.util.AesUtil;
import com.maozzi.common.util.HttpUtil;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jetbrains.annotations.NotNull;
import org.springframework.http.HttpHeaders;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 权限拦截器
 *
 * @author maozi
 */
public class AuthInterceptor implements HandlerInterceptor {
    /**
     * 主机
     */
    private final String host;

    /**
     * 查询用户信息URL
     */
    private final String userInfoUrl;

    /**
     * 查询acl用户信息URL
     */
    private final String aclUserInfoUrl;

    private final static Gson GSON = new Gson();

    public AuthInterceptor(AuthProperties authProperties) {
        this.host = authProperties.getHost();
        this.userInfoUrl = authProperties.getUserInfoUrl();
        this.aclUserInfoUrl = authProperties.getAclUserInfoUrl();
    }

    @Override
    public boolean preHandle(HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) {
        String url = request.getRequestURI();
        if (AuthConstant.ERROR_URLS.contains(url)
                || userInfoUrl.equalsIgnoreCase(url)
                || aclUserInfoUrl.equalsIgnoreCase(url)
        ) {
            return true;
        }

        String token = this.getToken(request);
        if (!StringUtils.hasText(token)) {
            // 未登录
            throw new BizException(BizCodeEnum.NEED_LOGIN);
        }

        Boolean hasPermission = this.checkUserHasPermission(token, handler);
        if (!hasPermission) {
            throw new BizException(BizCodeEnum.FORBIDDEN);
        }

        return true;
    }

    /**
     * 获取cookie token
     *
     * @param request 请求
     * @return 返回
     */
    private String getToken(HttpServletRequest request) {
        String token = request.getHeader(HttpHeaders.AUTHORIZATION);
        if (Objects.isNull(token) || token.isBlank()) {
            return null;
        }

        return token.replace("Bearer", "").replaceAll(" ", "");
    }

    /**
     * 检查用户是否拥有权限
     *
     * @param token 用户token
     * @return false - 无权限
     */
    private Boolean checkUserHasPermission(String token, Object handler) {
        RequirePermissions annotation = null;
        // 如果是SpringMVC请求
        if (handler instanceof HandlerMethod handlerMethod) {
            annotation = handlerMethod.getMethodAnnotation(RequirePermissions.class);
        }
        if (ObjectUtils.isEmpty(annotation)) {
            annotation = handler.getClass().getAnnotation(RequirePermissions.class);
        }

        // 发送请求
        Map<String, String> headers = new HashMap<>(1);
        headers.put("X-Requested-With", "XMLHttpRequest");
        Map<String, String> params = new HashMap<>(3);
        String timestamp = String.valueOf(System.currentTimeMillis());
        params.put("timestamp", timestamp);
        params.put("sign", AesUtil.encrypt(token, timestamp));
        params.put("token", token);
        String response = HttpUtil.sendGet(host + aclUserInfoUrl, headers, params);
        ResultVO<UserInfo> resultVO = GSON.fromJson(response, ResultVO.class);
        if (ObjectUtils.isEmpty(resultVO) || ObjectUtils.isEmpty(resultVO.getData())) {
            return Boolean.FALSE;
        }

        UserInfo userInfo = resultVO.getData();

        // 检查用户类型
        UserTypeEnum type = userInfo.getType();
        if (UserTypeEnum.NORMAL.equals(type)) {
            return Boolean.FALSE;
        }
        if (UserTypeEnum.SUPER_ADMIN.equals(type)) {
            return Boolean.TRUE;
        }

        // 检查角色
        String[] roles = annotation.role();
        List<String> roleList = userInfo.getRoles();
        if (!ObjectUtils.isEmpty(roles) && !ObjectUtils.isEmpty(roleList)) {
            List<String> list = Arrays.stream(roles).filter(roleList::contains).collect(Collectors.toList());
            return ObjectUtils.isEmpty(list) ? Boolean.FALSE : Boolean.TRUE;
        }

        // 检查权限码
        String[] codes = annotation.code();
        List<String> permissions = userInfo.getPermissions();
        if (!ObjectUtils.isEmpty(codes) && !ObjectUtils.isEmpty(permissions)) {
            List<String> list = Arrays.stream(codes).filter(permissions::contains).collect(Collectors.toList());
            return ObjectUtils.isEmpty(list) ? Boolean.FALSE : Boolean.TRUE;
        }

        return Boolean.FALSE;
    }

}
